/*
 * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.corba.se.impl.oa.poa;

import java.util.Collection;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;

import org.omg.CORBA.Policy;
import org.omg.CORBA.SystemException;

import org.omg.PortableServer.POA;
import org.omg.PortableServer.Servant;
import org.omg.PortableServer.POAManager;
import org.omg.PortableServer.AdapterActivator;
import org.omg.PortableServer.ServantManager;
import org.omg.PortableServer.ForwardRequest;
import org.omg.PortableServer.ThreadPolicy;
import org.omg.PortableServer.LifespanPolicy;
import org.omg.PortableServer.IdUniquenessPolicy;
import org.omg.PortableServer.IdAssignmentPolicy;
import org.omg.PortableServer.ImplicitActivationPolicy;
import org.omg.PortableServer.ServantRetentionPolicy;
import org.omg.PortableServer.RequestProcessingPolicy;
import org.omg.PortableServer.ThreadPolicyValue;
import org.omg.PortableServer.LifespanPolicyValue;
import org.omg.PortableServer.IdUniquenessPolicyValue;
import org.omg.PortableServer.IdAssignmentPolicyValue;
import org.omg.PortableServer.ImplicitActivationPolicyValue;
import org.omg.PortableServer.ServantRetentionPolicyValue;
import org.omg.PortableServer.RequestProcessingPolicyValue;
import org.omg.PortableServer.POAPackage.AdapterAlreadyExists;
import org.omg.PortableServer.POAPackage.AdapterNonExistent;
import org.omg.PortableServer.POAPackage.InvalidPolicy;
import org.omg.PortableServer.POAPackage.WrongPolicy;
import org.omg.PortableServer.POAPackage.WrongAdapter;
import org.omg.PortableServer.POAPackage.NoServant;
import org.omg.PortableServer.POAPackage.ServantAlreadyActive;
import org.omg.PortableServer.POAPackage.ObjectAlreadyActive;
import org.omg.PortableServer.POAPackage.ServantNotActive;
import org.omg.PortableServer.POAPackage.ObjectNotActive;

import org.omg.PortableInterceptor.ObjectReferenceFactory;
import org.omg.PortableInterceptor.ObjectReferenceTemplate;
import org.omg.PortableInterceptor.NON_EXISTENT;

import org.omg.IOP.TAG_INTERNET_IOP;

import com.sun.corba.se.spi.copyobject.CopierManager;
import com.sun.corba.se.spi.copyobject.ObjectCopier;
import com.sun.corba.se.spi.copyobject.ObjectCopierFactory;
import com.sun.corba.se.spi.oa.OADestroyed;
import com.sun.corba.se.spi.oa.OAInvocationInfo;
import com.sun.corba.se.spi.oa.ObjectAdapter;
import com.sun.corba.se.spi.oa.ObjectAdapterBase;
import com.sun.corba.se.spi.oa.ObjectAdapterFactory;
import com.sun.corba.se.spi.ior.ObjectKeyTemplate;
import com.sun.corba.se.spi.ior.ObjectId;
import com.sun.corba.se.spi.ior.ObjectAdapterId;
import com.sun.corba.se.spi.ior.IOR;
import com.sun.corba.se.spi.ior.IORFactories;
import com.sun.corba.se.spi.ior.IORTemplate;
import com.sun.corba.se.spi.ior.IORTemplateList;
import com.sun.corba.se.spi.ior.TaggedProfile;
import com.sun.corba.se.spi.ior.iiop.IIOPProfile;
import com.sun.corba.se.spi.ior.iiop.IIOPAddress;
import com.sun.corba.se.spi.ior.iiop.IIOPFactories;
import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.spi.protocol.ForwardException;
import com.sun.corba.se.spi.transport.SocketOrChannelAcceptor;

import com.sun.corba.se.impl.ior.POAObjectKeyTemplate;
import com.sun.corba.se.impl.ior.ObjectAdapterIdArray;
import com.sun.corba.se.impl.orbutil.ORBUtility;
import com.sun.corba.se.impl.orbutil.ORBConstants;
import com.sun.corba.se.impl.orbutil.concurrent.Sync;
import com.sun.corba.se.impl.orbutil.concurrent.SyncUtil;
import com.sun.corba.se.impl.orbutil.concurrent.ReentrantMutex;
import com.sun.corba.se.impl.orbutil.concurrent.CondVar;

/**
 * POAImpl is the implementation of the Portable Object Adapter. It
 * contains an implementation of the POA interfaces specified in
 * COBRA 2.3.1 chapter 11 (formal/99-10-07).  This implementation
 * is moving to comply with CORBA 3.0 due to the many clarifications
 * that have been made to the POA semantics since CORBA 2.3.1.
 * Specific comments have been added where 3.0 applies, but note that
 * we do not have the new 3.0 APIs yet.
 */
public class POAImpl extends ObjectAdapterBase implements POA {

  private boolean debug;

    /* POA creation takes place in 2 stages: first, the POAImpl constructor is
       called, then the initialize method is called.  This separation is
       needed because an AdapterActivator does not know the POAManager or
       the policies when
       the unknown_adapter method is invoked.  However, the POA must be created
       before the unknown_adapter method is invoked, so that the parent knows
       when concurrent attempts are made to create the same POA.
       Calling the POAImpl constructor results in a new POA in state STATE_START.
       Calling initialize( POAManager, Policies ) results in state STATE_RUN.
       Calling destroy results in STATE_DESTROY, which marks the beginning of
       POA destruction.
    */

  // Notes on concurrency.
  // The POA requires careful design for concurrency management to correctly
  // implement the specification and avoid deadlocks.  The order of acquiring
  // locks must respect the following locking hierarchy:
  //
  // 1. Lock POAs before POAManagers
  // 2. Lock a POA before locking its child POA
  //
  // Also note that there are 3 separate conditions on which threads may wait
  // in the POA, as defined by invokeCV, beingDestroyedCV, and
  // adapterActivatorCV.  This means that (for this reason as well as others)
  // we cannot simply use the standard Java synchronized primitive.
  // This implementation uses a modified version of Doug Lea's
  // util.concurrent (version 1.3.0) that supports reentrant
  // mutexes to handle the locking.  This will all be replaced by the new JSR
  // 166 concurrency primitives in J2SE 1.5 and later once the ORB moves to
  // J2SE 1.5.

  // POA state constants
  //
  // Note that ordering is important here: we must have the state defined in
  // this order so that ordered comparison is possible.
  // DO NOT CHANGE THE VALUES OF THE STATE CONSTANTS!!!  In particular, the
  // initialization related states must be lower than STATE_RUN.
  //
  // POA is created in STATE_START
  //
  // Valid state transitions:
  //
  // START to INIT                        after find_POA constructor call
  // START to RUN                         after initialize completes
  // INIT to INIT_DONE                    after initialize completes
  // INIT to DESTROYED                    after failed unknown_adapter
  // INIT_DONE to RUN                     after successful unknown_adapter
  // STATE_RUN to STATE_DESTROYING        after start of destruction
  // STATE_DESTROYING to STATE_DESTROYED  after destruction completes.

  private static final int STATE_START = 0; // constructor complete
  private static final int STATE_INIT = 1; // waiting for adapter activator
  private static final int STATE_INIT_DONE = 2; // adapter activator called create_POA
  private static final int STATE_RUN = 3; // initialized and running
  private static final int STATE_DESTROYING = 4; // being destroyed
  private static final int STATE_DESTROYED = 5; // destruction complete

  private String stateToString() {
    switch (state) {
      case STATE_START:
        return "START";
      case STATE_INIT:
        return "INIT";
      case STATE_INIT_DONE:
        return "INIT_DONE";
      case STATE_RUN:
        return "RUN";
      case STATE_DESTROYING:
        return "DESTROYING";
      case STATE_DESTROYED:
        return "DESTROYED";
      default:
        return "UNKNOWN(" + state + ")";
    }
  }

  // Current state of the POA
  private int state;

  // The POA request handler that performs all policy specific operations
  // Note that POAImpl handles all synchronization, so mediator is (mostly)
  // unsynchronized.
  private POAPolicyMediator mediator;

  // Representation of object adapter ID
  private int numLevels;          // counts depth of tree.  Root = 1.
  private ObjectAdapterId poaId; // the actual object adapter ID for this POA
  private String name;            // the name of this POA

  private POAManagerImpl manager; // This POA's POAManager
  private int uniquePOAId;       // ID for this POA that is unique relative
  // to the POAFactory, which has the same
  // lifetime as the ORB.
  private POAImpl parent;         // The POA that created this POA.
  private Map children;           // Map from name to POA of POAs created by
  // this POA.

  private AdapterActivator activator;
  private int invocationCount; // pending invocations on this POA.

  // Data used to control POA concurrency
  // XXX revisit for JSR 166

  // Master lock for all POA synchronization.  See lock and unlock.
  // package private for access by AOMEntry.
  Sync poaMutex;

  // Wait on this CV for AdapterActivator upcalls to complete
  private CondVar adapterActivatorCV;

  // Wait on this CV for all active invocations to complete
  private CondVar invokeCV;

  // Wait on this CV for the destroy method to complete doing its work
  private CondVar beingDestroyedCV;

  // thread local variable to store a boolean to detect deadlock in
  // POA.destroy().
  protected ThreadLocal isDestroying;

  // This includes the most important information for debugging
  // POA problems.
  public String toString() {
    return "POA[" + poaId.toString() +
        ", uniquePOAId=" + uniquePOAId +
        ", state=" + stateToString() +
        ", invocationCount=" + invocationCount + "]";
  }

  // package private for mediator implementations.
  boolean getDebug() {
    return debug;
  }

  // package private for access to servant to POA map
  static POAFactory getPOAFactory(ORB orb) {
    return (POAFactory) orb.getRequestDispatcherRegistry().
        getObjectAdapterFactory(ORBConstants.TRANSIENT_SCID);
  }

  // package private so that POAFactory can access it.
  static POAImpl makeRootPOA(ORB orb) {
    POAManagerImpl poaManager = new POAManagerImpl(getPOAFactory(orb),
        orb.getPIHandler());

    POAImpl result = new POAImpl(ORBConstants.ROOT_POA_NAME,
        null, orb, STATE_START);
    result.initialize(poaManager, Policies.rootPOAPolicies);

    return result;
  }

  // package private so that POAPolicyMediatorBase can access it.
  int getPOAId() {
    return uniquePOAId;
  }


  // package private so that POAPolicyMediator can access it.
  void lock() {
    SyncUtil.acquire(poaMutex);

    if (debug) {
      ORBUtility.dprint(this, "LOCKED poa " + this);
    }
  }

  // package private so that POAPolicyMediator can access it.
  void unlock() {
    if (debug) {
      ORBUtility.dprint(this, "UNLOCKED poa " + this);
    }

    poaMutex.release();
  }

  // package private so that DelegateImpl can access it.
  Policies getPolicies() {
    return mediator.getPolicies();
  }

  // Note that the parent POA must be locked when this constructor is called.
  private POAImpl(String name, POAImpl parent, ORB orb, int initialState) {
    super(orb);

    debug = orb.poaDebugFlag;

    if (debug) {
      ORBUtility.dprint(this, "Creating POA with name=" + name +
          " parent=" + parent);
    }

    this.state = initialState;
    this.name = name;
    this.parent = parent;
    children = new HashMap();
    activator = null;

    // This was done in initialize, but I moved it here
    // to get better searchability when tracing.
    uniquePOAId = getPOAFactory(orb).newPOAId();

    if (parent == null) {
      // This is the root POA, which counts as 1 level
      numLevels = 1;
    } else {
      // My level is one more than that of my parent
      numLevels = parent.numLevels + 1;

      parent.children.put(name, this);
    }

    // Get an array of all of the POA names in order to
    // create the poaid.
    String[] names = new String[numLevels];
    POAImpl poaImpl = this;
    int ctr = numLevels - 1;
    while (poaImpl != null) {
      names[ctr--] = poaImpl.name;
      poaImpl = poaImpl.parent;
    }

    poaId = new ObjectAdapterIdArray(names);

    invocationCount = 0;

    poaMutex = new ReentrantMutex(orb.poaConcurrencyDebugFlag);

    adapterActivatorCV = new CondVar(poaMutex,
        orb.poaConcurrencyDebugFlag);
    invokeCV = new CondVar(poaMutex,
        orb.poaConcurrencyDebugFlag);
    beingDestroyedCV = new CondVar(poaMutex,
        orb.poaConcurrencyDebugFlag);

    isDestroying = new ThreadLocal() {
      protected java.lang.Object initialValue() {
        return Boolean.FALSE;
      }
    };
  }

  // The POA lock must be held when this method is called.
  private void initialize(POAManagerImpl manager, Policies policies) {
    if (debug) {
      ORBUtility.dprint(this, "Initializing poa " + this +
          " with POAManager=" + manager + " policies=" + policies);
    }

    this.manager = manager;
    manager.addPOA(this);

    mediator = POAPolicyMediatorFactory.create(policies, this);

    // Construct the object key template
    int serverid = mediator.getServerId();
    int scid = mediator.getScid();
    String orbId = getORB().getORBData().getORBId();

    ObjectKeyTemplate oktemp = new POAObjectKeyTemplate(getORB(),
        scid, serverid, orbId, poaId);

    if (debug) {
      ORBUtility.dprint(this, "Initializing poa: oktemp=" + oktemp);
    }

    // Note that parent == null iff this is the root POA.
    // This was used to avoid executing interceptors on the RootPOA.
    // That is no longer necessary.
    boolean objectAdapterCreated = true; // parent != null ;

    // XXX extract codebase from policies and pass into initializeTemplate
    // after the codebase policy change is finalized.
    initializeTemplate(oktemp, objectAdapterCreated,
        policies,
        null, // codebase
        null, // manager id
        oktemp.getObjectAdapterId()
    );

    if (state == STATE_START) {
      state = STATE_RUN;
    } else if (state == STATE_INIT) {
      state = STATE_INIT_DONE;
    } else {
      throw lifecycleWrapper().illegalPoaStateTrans();
    }
  }

  // The poaMutex must be held when this method is called
  private boolean waitUntilRunning() {
    if (debug) {
      ORBUtility.dprint(this,
          "Calling waitUntilRunning on poa " + this);
    }

    while (state < STATE_RUN) {
      try {
        adapterActivatorCV.await();
      } catch (InterruptedException exc) {
        // NO-OP
      }
    }

    if (debug) {
      ORBUtility.dprint(this,
          "Exiting waitUntilRunning on poa " + this);
    }

    // Note that a POA could be destroyed while in STATE_INIT due to a
    // failure in the AdapterActivator upcall.
    return (state == STATE_RUN);
  }

  // This method checks that the AdapterActivator finished the
  // initialization of a POA activated in find_POA.  This is
  // determined by checking the state of the POA.  If the state is
  // STATE_INIT, the AdapterActivator did not complete the
  // inialization.  In this case, we destroy the POA that was
  // partially created and return false.  Otherwise, we return true.
  // In any case, we must wake up all threads waiting for the adapter
  // activator, either to continue their invocations, or to return
  // errors to their client.
  //
  // The poaMutex must NOT be held when this method is called.
  private boolean destroyIfNotInitDone() {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this,
            "Calling destroyIfNotInitDone on poa " + this);
      }

      boolean success = (state == STATE_INIT_DONE);

      if (success) {
        state = STATE_RUN;
      } else {
        // Don't just use destroy, because the check for
        // deadlock is too general, and can prevent this from
        // functioning properly.
        DestroyThread destroyer = new DestroyThread(false, debug);
        destroyer.doIt(this, true);
      }

      return success;
    } finally {
      adapterActivatorCV.broadcast();

      if (debug) {
        ORBUtility.dprint(this,
            "Exiting destroyIfNotInitDone on poa " + this);
      }

      unlock();
    }
  }

  private byte[] internalReferenceToId(
      org.omg.CORBA.Object reference) throws WrongAdapter {
    IOR ior = ORBUtility.getIOR(reference);
    IORTemplateList thisTemplate = ior.getIORTemplates();

    ObjectReferenceFactory orf = getCurrentFactory();
    IORTemplateList poaTemplate =
        IORFactories.getIORTemplateList(orf);

    if (!poaTemplate.isEquivalent(thisTemplate)) {
      throw new WrongAdapter();
    }

    // Extract the ObjectId from the first TaggedProfile in the IOR.
    // If ior was created in this POA, the same ID was used for
    // every profile through the profile templates in the currentFactory,
    // so we will get the same result from any profile.
    Iterator iter = ior.iterator();
    if (!iter.hasNext()) {
      throw iorWrapper().noProfilesInIor();
    }
    TaggedProfile prof = (TaggedProfile) (iter.next());
    ObjectId oid = prof.getObjectId();

    return oid.getId();
  }

  // Converted from anonymous class to local class
  // so that we can call performDestroy() directly.
  static class DestroyThread extends Thread {

    private boolean wait;
    private boolean etherealize;
    private boolean debug;
    private POAImpl thePoa;

    public DestroyThread(boolean etherealize, boolean debug) {
      this.etherealize = etherealize;
      this.debug = debug;
    }

    public void doIt(POAImpl thePoa, boolean wait) {
      if (debug) {
        ORBUtility.dprint(this,
            "Calling DestroyThread.doIt(thePOA=" + thePoa +
                " wait=" + wait + " etherealize=" + etherealize);
      }

      this.thePoa = thePoa;
      this.wait = wait;

      if (wait) {
        run();
      } else {
        // Catch exceptions since setDaemon can cause a
        // security exception to be thrown under netscape
        // in the Applet mode
        try {
          setDaemon(true);
        } catch (Exception e) {
        }
        start();
      }
    }

    public void run() {
      Set destroyedPOATemplates = new HashSet();

      performDestroy(thePoa, destroyedPOATemplates);

      Iterator iter = destroyedPOATemplates.iterator();
      ObjectReferenceTemplate[] orts = new ObjectReferenceTemplate[
          destroyedPOATemplates.size()];
      int index = 0;
      while (iter.hasNext()) {
        orts[index++] = (ObjectReferenceTemplate) iter.next();
      }

      thePoa.getORB().getPIHandler().adapterStateChanged(orts,
          NON_EXISTENT.value);
    }

    // Returns true if destruction must be completed, false
    // if not, which means that another thread is already
    // destroying poa.
    private boolean prepareForDestruction(POAImpl poa,
        Set destroyedPOATemplates) {
      POAImpl[] childPoas = null;

      // Note that we do not synchronize on this, since this is
      // the PerformDestroy instance, not the POA.
      try {
        poa.lock();

        if (debug) {
          ORBUtility.dprint(this,
              "Calling performDestroy on poa " + poa);
        }

        if (poa.state <= STATE_RUN) {
          poa.state = STATE_DESTROYING;
        } else {
          // destroy may be called multiple times, and each call
          // is allowed to proceed with its own setting of the wait
          // flag, but the etherealize value is used from the first
          // call to destroy.  Also all children should be destroyed
          // before the parent POA.  If the poa is already destroyed,
          // we can just return.  If the poa has started destruction,
          // but not completed, and wait is true, we need to wait
          // until destruction is complete, then just return.
          if (wait) {
            while (poa.state != STATE_DESTROYED) {
              try {
                poa.beingDestroyedCV.await();
              } catch (InterruptedException exc) {
                // NO-OP
              }
            }
          }

          return false;
        }

        poa.isDestroying.set(Boolean.TRUE);

        // Make a copy since we can't hold the lock while destroying
        // the children, and an iterator is not deletion-safe.
        childPoas = (POAImpl[]) poa.children.values().toArray(
            new POAImpl[0]);
      } finally {
        poa.unlock();
      }

      // We are not holding the POA mutex here to avoid holding it
      // while destroying the POA's children, since this may involve
      // upcalls to etherealize methods.

      for (int ctr = 0; ctr < childPoas.length; ctr++) {
        performDestroy(childPoas[ctr], destroyedPOATemplates);
      }

      return true;
    }

    public void performDestroy(POAImpl poa, Set destroyedPOATemplates) {
      if (!prepareForDestruction(poa, destroyedPOATemplates)) {
        return;
      }

      // NOTE: If we are here, poa is in STATE_DESTROYING state. All
      // other state checks are taken care of in prepareForDestruction.
      // No other threads may either be starting new invocations
      // by calling enter or starting to destroy poa.  There may
      // still be pending invocations.

      POAImpl parent = poa.parent;
      boolean isRoot = parent == null;

      try {
        // Note that we must lock the parent before the child.
        // The parent lock is required (if poa is not the root)
        // to safely remove poa from parent's children Map.
        if (!isRoot) {
          parent.lock();
        }

        try {
          poa.lock();

          completeDestruction(poa, parent,
              destroyedPOATemplates);
        } finally {
          poa.unlock();

          if (isRoot)
          // We have just destroyed the root POA, so we need to
          // make sure that the next call to
          // resolve_initial_reference( "RootPOA" )
          // will recreate a valid root POA.
          {
            poa.manager.getFactory().registerRootPOA();
          }
        }
      } finally {
        if (!isRoot) {
          parent.unlock();
          poa.parent = null;
        }
      }
    }

    private void completeDestruction(POAImpl poa, POAImpl parent,
        Set destroyedPOATemplates) {
      if (debug) {
        ORBUtility.dprint(this,
            "Calling completeDestruction on poa " + poa);
      }

      try {
        while (poa.invocationCount != 0) {
          try {
            poa.invokeCV.await();
          } catch (InterruptedException ex) {
            // NO-OP
          }
        }

        if (poa.mediator != null) {
          if (etherealize) {
            poa.mediator.etherealizeAll();
          }

          poa.mediator.clearAOM();
        }

        if (poa.manager != null) {
          poa.manager.removePOA(poa);
        }

        if (parent != null) {
          parent.children.remove(poa.name);
        }

        destroyedPOATemplates.add(poa.getAdapterTemplate());
      } catch (Throwable thr) {
        if (thr instanceof ThreadDeath) {
          throw (ThreadDeath) thr;
        }

        poa.lifecycleWrapper().unexpectedException(thr, poa.toString());
      } finally {
        poa.state = STATE_DESTROYED;
        poa.beingDestroyedCV.broadcast();
        poa.isDestroying.set(Boolean.FALSE);

        if (debug) {
          ORBUtility.dprint(this,
              "Exiting completeDestruction on poa " + poa);
        }
      }
    }
  }

  void etherealizeAll() {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this,
            "Calling etheralizeAll on poa " + this);
      }

      mediator.etherealizeAll();
    } finally {
      if (debug) {
        ORBUtility.dprint(this,
            "Exiting etheralizeAll on poa " + this);
      }

      unlock();
    }
  }

  //*******************************************************************
  // Public POA API
  //*******************************************************************

  /**
   * <code>create_POA</code>
   * <b>Section 3.3.8.2</b>
   */
  public POA create_POA(String name, POAManager
      theManager, Policy[] policies) throws AdapterAlreadyExists,
      InvalidPolicy {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this, "Calling create_POA(name=" + name +
            " theManager=" + theManager + " policies=" + policies +
            ") on poa " + this);
      }

      // We cannot create children of a POA that is (being) destroyed.
      // This has been added to the CORBA 3.0 spec.
      if (state > STATE_RUN) {
        throw omgLifecycleWrapper().createPoaDestroy();
      }

      POAImpl poa = (POAImpl) (children.get(name));

      if (poa == null) {
        poa = new POAImpl(name, this, getORB(), STATE_START);
      }

      try {
        poa.lock();

        if (debug) {
          ORBUtility.dprint(this,
              "Calling create_POA: new poa is " + poa);
        }

        if ((poa.state != STATE_START) && (poa.state != STATE_INIT)) {
          throw new AdapterAlreadyExists();
        }

        POAManagerImpl newManager = (POAManagerImpl) theManager;
        if (newManager == null) {
          newManager = new POAManagerImpl(manager.getFactory(),
              manager.getPIHandler());
        }

        int defaultCopierId =
            getORB().getCopierManager().getDefaultId();
        Policies POAPolicies =
            new Policies(policies, defaultCopierId);

        poa.initialize(newManager, POAPolicies);

        return poa;
      } finally {
        poa.unlock();
      }
    } finally {
      unlock();
    }
  }

  /**
   * <code>find_POA</code>
   * <b>Section 3.3.8.3</b>
   */
  public POA find_POA(String name, boolean activate)
      throws AdapterNonExistent {
    POAImpl found = null;
    AdapterActivator act = null;

    lock();

    if (debug) {
      ORBUtility.dprint(this, "Calling find_POA(name=" + name +
          " activate=" + activate + ") on poa " + this);
    }

    found = (POAImpl) children.get(name);

    if (found != null) {
      if (debug) {
        ORBUtility.dprint(this,
            "Calling find_POA: found poa " + found);
      }

      try {
        found.lock();

        // Do not hold the parent POA lock while
        // waiting for child to complete initialization.
        unlock();

        // Make sure that the child has completed its initialization,
        // if it was created by an AdapterActivator, otherwise throw
        // a standard TRANSIENT exception with minor code 4 (see
        // CORBA 3.0 11.3.9.3, in reference to unknown_adapter)
        if (!found.waitUntilRunning()) {
          throw omgLifecycleWrapper().poaDestroyed();
        }

        // Note that found may be in state DESTROYING or DESTROYED at
        // this point.  That's OK, since destruction could start at
        // any time.
      } finally {
        found.unlock();
      }
    } else {
      try {
        if (debug) {
          ORBUtility.dprint(this,
              "Calling find_POA: no poa found");
        }

        if (activate && (activator != null)) {
          // Create a child, but don't initialize it.  The newly
          // created POA will be in state STATE_START, which will
          // cause other calls to find_POA that are creating the same
          // POA to block on the waitUntilRunning call above.
          // Initialization must be completed by a call to create_POA
          // inside the unknown_adapter upcall.  Note that
          // this.poaMutex must be held here so that this.children
          // can be safely updated.  The state is set to STATE_INIT
          // so that initialize can make the correct state transition
          // when create_POA is called inside the AdapterActivator.
          // This avoids activating the new POA too soon
          // by transitioning to STATE_RUN after unknown_adapter
          // returns.
          found = new POAImpl(name, this, getORB(), STATE_INIT);

          if (debug) {
            ORBUtility.dprint(this,
                "Calling find_POA: created poa " + found);
          }

          act = activator;
        } else {
          throw new AdapterNonExistent();
        }
      } finally {
        unlock();
      }
    }

    // assert (found != null)
    // assert not holding this.poaMutex OR found.poaMutex

    // We must not hold either this.poaMutex or found.poaMutex here while
    // waiting for intialization of found to complete to prevent possible
    // deadlocks.

    if (act != null) {
      boolean status = false;
      boolean adapterResult = false;

      if (debug) {
        ORBUtility.dprint(this,
            "Calling find_POA: calling AdapterActivator");
      }

      try {
        // Prevent more than one thread at a time from executing in act
        // in case act is shared between multiple POAs.
        synchronized (act) {
          status = act.unknown_adapter(this, name);
        }
      } catch (SystemException exc) {
        throw omgLifecycleWrapper().adapterActivatorException(exc,
            name, poaId.toString());
      } catch (Throwable thr) {
        // ignore most non-system exceptions, but log them for
        // diagnostic purposes.
        lifecycleWrapper().unexpectedException(thr, this.toString());

        if (thr instanceof ThreadDeath) {
          throw (ThreadDeath) thr;
        }
      } finally {
        // At this point, we have completed adapter activation.
        // Whether this was successful or not, we must call
        // destroyIfNotInitDone so that calls to enter() and create_POA()
        // that are waiting can execute again.  Failing to do this
        // will cause the system to hang in complex tests.
        adapterResult = found.destroyIfNotInitDone();
      }

      if (status) {
        if (!adapterResult) {
          throw omgLifecycleWrapper().adapterActivatorException(name,
              poaId.toString());
        }
      } else {
        if (debug) {
          ORBUtility.dprint(this,
              "Calling find_POA: AdapterActivator returned false");
        }

        // OMG Issue 3740 is resolved to throw AdapterNonExistent if
        // unknown_adapter() returns false.
        throw new AdapterNonExistent();
      }
    }

    return found;
  }

  /**
   * <code>destroy</code>
   * <b>Section 3.3.8.4</b>
   */
  public void destroy(boolean etherealize, boolean wait_for_completion) {
    // This is to avoid deadlock
    if (wait_for_completion && getORB().isDuringDispatch()) {
      throw lifecycleWrapper().destroyDeadlock();
    }

    DestroyThread destroyer = new DestroyThread(etherealize, debug);
    destroyer.doIt(this, wait_for_completion);
  }

  /**
   * <code>create_thread_policy</code>
   * <b>Section 3.3.8.5</b>
   */
  public ThreadPolicy create_thread_policy(
      ThreadPolicyValue value) {
    return new ThreadPolicyImpl(value);
  }

  /**
   * <code>create_lifespan_policy</code>
   * <b>Section 3.3.8.5</b>
   */
  public LifespanPolicy create_lifespan_policy(
      LifespanPolicyValue value) {
    return new LifespanPolicyImpl(value);
  }

  /**
   * <code>create_id_uniqueness_policy</code>
   * <b>Section 3.3.8.5</b>
   */
  public IdUniquenessPolicy create_id_uniqueness_policy(
      IdUniquenessPolicyValue value) {
    return new IdUniquenessPolicyImpl(value);
  }

  /**
   * <code>create_id_assignment_policy</code>
   * <b>Section 3.3.8.5</b>
   */
  public IdAssignmentPolicy create_id_assignment_policy(
      IdAssignmentPolicyValue value) {
    return new IdAssignmentPolicyImpl(value);
  }

  /**
   * <code>create_implicit_activation_policy</code>
   * <b>Section 3.3.8.5</b>
   */
  public ImplicitActivationPolicy create_implicit_activation_policy(
      ImplicitActivationPolicyValue value) {
    return new ImplicitActivationPolicyImpl(value);
  }

  /**
   * <code>create_servant_retention_policy</code>
   * <b>Section 3.3.8.5</b>
   */
  public ServantRetentionPolicy create_servant_retention_policy(
      ServantRetentionPolicyValue value) {
    return new ServantRetentionPolicyImpl(value);
  }

  /**
   * <code>create_request_processing_policy</code>
   * <b>Section 3.3.8.5</b>
   */
  public RequestProcessingPolicy create_request_processing_policy(
      RequestProcessingPolicyValue value) {
    return new RequestProcessingPolicyImpl(value);
  }

  /**
   * <code>the_name</code>
   * <b>Section 3.3.8.6</b>
   */
  public String the_name() {
    try {
      lock();

      return name;
    } finally {
      unlock();
    }
  }

  /**
   * <code>the_parent</code>
   * <b>Section 3.3.8.7</b>
   */
  public POA the_parent() {
    try {
      lock();

      return parent;
    } finally {
      unlock();
    }
  }

  /**
   * <code>the_children</code>
   */
  public org.omg.PortableServer.POA[] the_children() {
    try {
      lock();

      Collection coll = children.values();
      int size = coll.size();
      POA[] result = new POA[size];
      int index = 0;
      Iterator iter = coll.iterator();
      while (iter.hasNext()) {
        POA poa = (POA) (iter.next());
        result[index++] = poa;
      }

      return result;
    } finally {
      unlock();
    }
  }

  /**
   * <code>the_POAManager</code>
   * <b>Section 3.3.8.8</b>
   */
  public POAManager the_POAManager() {
    try {
      lock();

      return manager;
    } finally {
      unlock();
    }
  }

  /**
   * <code>the_activator</code>
   * <b>Section 3.3.8.9</b>
   */
  public AdapterActivator the_activator() {
    try {
      lock();

      return activator;
    } finally {
      unlock();
    }
  }

  /**
   * <code>the_activator</code>
   * <b>Section 3.3.8.9</b>
   */
  public void the_activator(AdapterActivator activator) {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this, "Calling the_activator on poa " +
            this + " activator=" + activator);
      }

      this.activator = activator;
    } finally {
      unlock();
    }
  }

  /**
   * <code>get_servant_manager</code>
   * <b>Section 3.3.8.10</b>
   */
  public ServantManager get_servant_manager() throws WrongPolicy {
    try {
      lock();

      return mediator.getServantManager();
    } finally {
      unlock();
    }
  }

  /**
   * <code>set_servant_manager</code>
   * <b>Section 3.3.8.10</b>
   */
  public void set_servant_manager(ServantManager servantManager)
      throws WrongPolicy {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this, "Calling set_servant_manager on poa " +
            this + " servantManager=" + servantManager);
      }

      mediator.setServantManager(servantManager);
    } finally {
      unlock();
    }
  }

  /**
   * <code>get_servant</code>
   * <b>Section 3.3.8.12</b>
   */
  public Servant get_servant() throws NoServant, WrongPolicy {
    try {
      lock();

      return mediator.getDefaultServant();
    } finally {
      unlock();
    }
  }

  /**
   * <code>set_servant</code>
   * <b>Section 3.3.8.13</b>
   */
  public void set_servant(Servant defaultServant)
      throws WrongPolicy {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this, "Calling set_servant on poa " +
            this + " defaultServant=" + defaultServant);
      }

      mediator.setDefaultServant(defaultServant);
    } finally {
      unlock();
    }
  }

  /**
   * <code>activate_object</code>
   * <b>Section 3.3.8.14</b>
   */
  public byte[] activate_object(Servant servant)
      throws ServantAlreadyActive, WrongPolicy {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this,
            "Calling activate_object on poa " + this +
                " (servant=" + servant + ")");
      }

      // Allocate a new system-generated object-id.
      // This will throw WrongPolicy if not SYSTEM_ID
      // policy.
      byte[] id = mediator.newSystemId();

      try {
        mediator.activateObject(id, servant);
      } catch (ObjectAlreadyActive oaa) {
        // This exception can not occur in this case,
        // since id is always brand new.
        //
      }

      return id;
    } finally {
      if (debug) {
        ORBUtility.dprint(this,
            "Exiting activate_object on poa " + this);
      }

      unlock();
    }
  }

  /**
   * <code>activate_object_with_id</code>
   * <b>Section 3.3.8.15</b>
   */
  public void activate_object_with_id(byte[] id,
      Servant servant)
      throws ObjectAlreadyActive, ServantAlreadyActive, WrongPolicy {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this,
            "Calling activate_object_with_id on poa " + this +
                " (servant=" + servant + " id=" + id + ")");
      }

      // Clone the id to avoid possible errors due to aliasing
      // (e.g. the client passes the id in and then changes it later).
      byte[] idClone = (byte[]) (id.clone());

      mediator.activateObject(idClone, servant);
    } finally {
      if (debug) {
        ORBUtility.dprint(this,
            "Exiting activate_object_with_id on poa " + this);
      }

      unlock();
    }
  }

  /**
   * <code>deactivate_object</code>
   * <b>3.3.8.16</b>
   */
  public void deactivate_object(byte[] id)
      throws ObjectNotActive, WrongPolicy {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this,
            "Calling deactivate_object on poa " + this +
                " (id=" + id + ")");
      }

      mediator.deactivateObject(id);
    } finally {
      if (debug) {
        ORBUtility.dprint(this,
            "Exiting deactivate_object on poa " + this);
      }

      unlock();
    }
  }

  /**
   * <code>create_reference</code>
   * <b>3.3.8.17</b>
   */
  public org.omg.CORBA.Object create_reference(String repId)
      throws WrongPolicy {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this, "Calling create_reference(repId=" +
            repId + ") on poa " + this);
      }

      return makeObject(repId, mediator.newSystemId());
    } finally {
      unlock();
    }
  }

  /**
   * <code>create_reference_with_id</code>
   * <b>3.3.8.18</b>
   */
  public org.omg.CORBA.Object
  create_reference_with_id(byte[] oid, String repId) {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this,
            "Calling create_reference_with_id(oid=" +
                oid + " repId=" + repId + ") on poa " + this);
      }

      // Clone the id to avoid possible errors due to aliasing
      // (e.g. the client passes the id in and then changes it later).
      byte[] idClone = (byte[]) (oid.clone());

      return makeObject(repId, idClone);
    } finally {
      unlock();
    }
  }

  /**
   * <code>servant_to_id</code>
   * <b>3.3.8.19</b>
   */
  public byte[] servant_to_id(Servant servant)
      throws ServantNotActive, WrongPolicy {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this, "Calling servant_to_id(servant=" +
            servant + ") on poa " + this);
      }

      return mediator.servantToId(servant);
    } finally {
      unlock();
    }
  }

  /**
   * <code>servant_to_reference</code>
   * <b>3.3.8.20</b>
   */
  public org.omg.CORBA.Object servant_to_reference(Servant servant)
      throws ServantNotActive, WrongPolicy {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this,
            "Calling servant_to_reference(servant=" +
                servant + ") on poa " + this);
      }

      byte[] oid = mediator.servantToId(servant);
      String repId = servant._all_interfaces(this, oid)[0];
      return create_reference_with_id(oid, repId);
    } finally {
      unlock();
    }
  }

  /**
   * <code>reference_to_servant</code>
   * <b>3.3.8.21</b>
   */
  public Servant reference_to_servant(org.omg.CORBA.Object reference)
      throws ObjectNotActive, WrongPolicy, WrongAdapter {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this,
            "Calling reference_to_servant(reference=" +
                reference + ") on poa " + this);
      }

      if (state >= STATE_DESTROYING) {
        throw lifecycleWrapper().adapterDestroyed();
      }

      // reference_to_id should throw WrongAdapter
      // if the objref was not created by this POA
      byte[] id = internalReferenceToId(reference);

      return mediator.idToServant(id);
    } finally {
      unlock();
    }
  }

  /**
   * <code>reference_to_id</code>
   * <b>3.3.8.22</b>
   */
  public byte[] reference_to_id(org.omg.CORBA.Object reference)
      throws WrongAdapter, WrongPolicy {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this, "Calling reference_to_id(reference=" +
            reference + ") on poa " + this);
      }

      if (state >= STATE_DESTROYING) {
        throw lifecycleWrapper().adapterDestroyed();
      }

      return internalReferenceToId(reference);
    } finally {
      unlock();
    }
  }

  /**
   * <code>id_to_servant</code>
   * <b>3.3.8.23</b>
   */
  public Servant id_to_servant(byte[] id)
      throws ObjectNotActive, WrongPolicy {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this, "Calling id_to_servant(id=" +
            id + ") on poa " + this);
      }

      if (state >= STATE_DESTROYING) {
        throw lifecycleWrapper().adapterDestroyed();
      }
      return mediator.idToServant(id);
    } finally {
      unlock();
    }
  }

  /**
   * <code>id_to_reference</code>
   * <b>3.3.8.24</b>
   */
  public org.omg.CORBA.Object id_to_reference(byte[] id)
      throws ObjectNotActive, WrongPolicy

  {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this, "Calling id_to_reference(id=" +
            id + ") on poa " + this);
      }

      if (state >= STATE_DESTROYING) {
        throw lifecycleWrapper().adapterDestroyed();
      }

      Servant s = mediator.idToServant(id);
      String repId = s._all_interfaces(this, id)[0];
      return makeObject(repId, id);
    } finally {
      unlock();
    }
  }

  /**
   * <code>id</code>
   * <b>11.3.8.26 in ptc/00-08-06</b>
   */
  public byte[] id() {
    try {
      lock();

      return getAdapterId();
    } finally {
      unlock();
    }
  }

  //***************************************************************
  //Implementation of ObjectAdapter interface
  //***************************************************************

  public Policy getEffectivePolicy(int type) {
    return mediator.getPolicies().get_effective_policy(type);
  }

  public int getManagerId() {
    return manager.getManagerId();
  }

  public short getState() {
    return manager.getORTState();
  }

  public String[] getInterfaces(java.lang.Object servant, byte[] objectId) {
    Servant serv = (Servant) servant;
    return serv._all_interfaces(this, objectId);
  }

  protected ObjectCopierFactory getObjectCopierFactory() {
    int copierId = mediator.getPolicies().getCopierId();
    CopierManager cm = getORB().getCopierManager();
    return cm.getObjectCopierFactory(copierId);
  }

  public void enter() throws OADestroyed {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this, "Calling enter on poa " + this);
      }

      // Avoid deadlock if this is the thread that is processing the
      // POA.destroy because this is the only thread that can notify
      // waiters on beingDestroyedCV.  This can happen if an
      // etherealize upcall invokes a method on a colocated object
      // served by this POA.
      while ((state == STATE_DESTROYING) &&
          (isDestroying.get() == Boolean.FALSE)) {
        try {
          beingDestroyedCV.await();
        } catch (InterruptedException ex) {
          // NO-OP
        }
      }

      if (!waitUntilRunning()) {
        throw new OADestroyed();
      }

      invocationCount++;
    } finally {
      if (debug) {
        ORBUtility.dprint(this, "Exiting enter on poa " + this);
      }

      unlock();
    }

    manager.enter();
  }

  public void exit() {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this, "Calling exit on poa " + this);
      }

      invocationCount--;

      if ((invocationCount == 0) && (state == STATE_DESTROYING)) {
        invokeCV.broadcast();
      }
    } finally {
      if (debug) {
        ORBUtility.dprint(this, "Exiting exit on poa " + this);
      }

      unlock();
    }

    manager.exit();
  }

  public void getInvocationServant(OAInvocationInfo info) {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this,
            "Calling getInvocationServant on poa " + this);
      }

      java.lang.Object servant = null;

      try {
        servant = mediator.getInvocationServant(info.id(),
            info.getOperation());
      } catch (ForwardRequest freq) {
        throw new ForwardException(getORB(), freq.forward_reference);
      }

      info.setServant(servant);
    } finally {
      if (debug) {
        ORBUtility.dprint(this,
            "Exiting getInvocationServant on poa " + this);
      }

      unlock();
    }
  }

  public org.omg.CORBA.Object getLocalServant(byte[] objectId) {
    return null;
  }

  /**
   * Called from the subcontract to let this POA cleanup after an
   * invocation. Note: If getServant was called, then returnServant
   * MUST be called, even in the case of exceptions.  This may be
   * called multiple times for a single request.
   */
  public void returnServant() {
    try {
      lock();

      if (debug) {
        ORBUtility.dprint(this,
            "Calling returnServant on poa " + this);
      }

      mediator.returnServant();
    } catch (Throwable thr) {
      if (debug) {
        ORBUtility.dprint(this,
            "Exception " + thr + " in returnServant on poa " + this);
      }

      if (thr instanceof Error) {
        throw (Error) thr;
      } else if (thr instanceof RuntimeException) {
        throw (RuntimeException) thr;
      }

    } finally {
      if (debug) {
        ORBUtility.dprint(this,
            "Exiting returnServant on poa " + this);
      }

      unlock();
    }
  }
}
